use std::fmt::{self};

use super::OdessSampleRecorder;
pub struct BackupStatistics {
	read_phase_time:u128,
	split_phase_time:u128,
	hash_phase_time:u128,
	dedup_phase_time:u128,
	extract_phase_time:u128,
	matching_phase_time:u128,
	read_base_phase_time:u128,
	delta_phase_time:u128,
	write_phase_time:u128,
	total_time:u128,
	origin_len:usize,
	after_dedup_len:usize,
	after_delta_len:usize,
	base_chunk_len:usize,
	delta_chunk_origin_len:usize,
	gear_hash_time:u128,
	pack_feature_time:u128,
	odess_sample_num:usize,
	odess_sample_recorder:OdessSampleRecorder,
}

impl BackupStatistics {
	pub fn new() -> Self {
		Self {
			read_phase_time:0,
			split_phase_time:0,
			hash_phase_time:0,
			dedup_phase_time:0,
			extract_phase_time:0,
			matching_phase_time:0,
			read_base_phase_time:0,
			delta_phase_time:0,
			write_phase_time:0,
			total_time:0,
			origin_len:0,
			after_dedup_len:0,
			after_delta_len:0,
			base_chunk_len:0,
			delta_chunk_origin_len:0,
			gear_hash_time:0,
			pack_feature_time:0,
			odess_sample_num:0,
			odess_sample_recorder:OdessSampleRecorder::new(),
		}
	}

	pub fn set_read_phase_time(&mut self,value:u128) {
		self.read_phase_time = value;
	}

	pub fn set_split_phase_time(&mut self,value:u128) {
		self.split_phase_time = value;
	}

	pub fn set_hash_phase_time(&mut self,value:u128) {
		self.hash_phase_time = value;
	}

	pub fn set_dedup_phase_time(&mut self,value:u128) {
		self.dedup_phase_time = value;
	}

	pub fn set_extract_phase_time(&mut self,value:u128) {
		self.extract_phase_time = value;
	}

	pub fn set_matching_phase_time(&mut self,value:u128) {
		self.matching_phase_time = value;
	}

	pub fn set_read_base_phase_time(&mut self,value:u128) {
		self.read_base_phase_time = value;
	}

	pub fn set_delta_phase_time(&mut self,value:u128) {
		self.delta_phase_time = value;
	}

	pub fn set_write_phase_time(&mut self,value:u128) {
		self.write_phase_time = value;
	}

	pub fn set_total_time(&mut self,value:u128) {
		self.total_time = value;
	}

	pub fn set_origin_len(&mut self,value:usize) {
		self.origin_len = value;
	}

	pub fn set_after_dedup_len(&mut self,value:usize) {
		self.after_dedup_len = value;
	}

	pub fn set_after_delta_len(&mut self,value:usize) {
		self.after_delta_len = value;
	}

	pub fn set_base_chunk_len(&mut self,value:usize) {
		self.base_chunk_len = value;
	}

	pub fn set_delta_chunk_origin_len(&mut self,value:usize) {
		self.delta_chunk_origin_len = value;
	}

	pub fn set_gear_hash_time(&mut self, value:u128) {
		self.gear_hash_time = value;
	}

	pub fn set_pack_feature_time(&mut self, value:u128) {
		self.pack_feature_time = value;
	}

	pub fn set_odess_sample_time(&mut self, value:usize) {
		self.odess_sample_num = value;
	}

	pub fn dedup_ratio(&self) -> f64 {
		if self.origin_len == 0 {
			return 0f64;
		} else {
			let dedup_len = self.origin_len.saturating_sub(self.after_dedup_len) as f64;
			let total_len = self.origin_len as f64;
			return dedup_len / total_len * 100f64;
		}
	}

	pub fn delta_ratio(&self) -> f64 {
		if self.origin_len == 0 {
			return 0f64;
		} else {
			let delta_len = self.after_dedup_len.saturating_sub(self.after_delta_len) as f64;
			let total_len = self.origin_len as f64;
			return delta_len / total_len * 100f64;
		}
	}

	pub fn total_ratio(&self) -> f64 {
		if self.origin_len == 0 {
			return 0f64;
		} else {
			let delta_len = self.origin_len.saturating_sub(self.after_delta_len) as f64;
			let total_len = self.origin_len as f64;
			return delta_len / total_len * 100f64;
		}
	}

	pub fn to_simple_table(&self) -> String {
		format!("read\tsplit\thash\tdedup\textract\tmatching\tbase\tdelta\twrite\ttotal_time\ttotal_len\tafter_dedup\tafter_delta\tbase_chunk\tdelta_chunk_origin\tdedup_ratio\tdelta_ratio\ttotal_ratio\tgear_hash\tpack_feature\todess_sample\n
{}us\t{}us\t{}us\t{}us\t{}us\t{}us\t{}us\t{}us\t{}us\t{}us\t{}B\t{}B\t{}B\t{}B\t{}B\t{:.2}%\t{:.2}%\t{:.2}%\t{}us\t{}us\t{}",
			self.read_phase_time,
			self.split_phase_time,
			self.hash_phase_time,
			self.dedup_phase_time,
			self.extract_phase_time,
			self.matching_phase_time,
			self.read_base_phase_time,
			self.delta_phase_time,
			self.write_phase_time,
			self.total_time,
			self.origin_len,
			self.after_dedup_len,
			self.after_delta_len,
			self.base_chunk_len,
			self.delta_chunk_origin_len,
			self.dedup_ratio(),
			self.delta_ratio(),
			self.total_ratio(),
			self.gear_hash_time,
			self.pack_feature_time,
			self.odess_sample_num
		)
	}

// 	pub fn to_simple_table(&self) -> String {
// 		format!("read\tsplit\thash\tdedup\textract\tmatching\tbase\tdelta\twrite\ttotal_time\ttotal_len\tafter_dedup\tafter_delta\tbase_chunk\tdelta_chunk_origin\tdedup_ratio\tdelta_ratio\ttotal_ratio\tgear_hash\tpack_feature\todess_sample\n
// {}\t{}\t{}\t{}\t{}\t{}\t{}\t{}\t{}\t{}\t{}\t{}\t{}\t{}\t{}\t{:.2}%\t{:.2}%\t{:.2}%\t{}\t{}\t{}",
// 			self.read_phase_time,
// 			self.split_phase_time,
// 			self.hash_phase_time,
// 			self.dedup_phase_time,
// 			self.extract_phase_time,
// 			self.matching_phase_time,
// 			self.read_base_phase_time,
// 			self.delta_phase_time,
// 			self.write_phase_time,
// 			self.total_time,
// 			self.origin_len,
// 			self.after_dedup_len,
// 			self.after_delta_len,
// 			self.base_chunk_len,
// 			self.delta_chunk_origin_len,
// 			self.dedup_ratio(),
// 			self.delta_ratio(),
// 			self.total_ratio(),
// 			self.gear_hash_time,
// 			self.pack_feature_time,
// 			self.odess_sample_num
// 		)
// 	}

	pub fn to_result(&self,is_table:Option<bool>) -> String {
		match is_table {
			Some(true) => self.to_simple_table(),
			_ => format!("{}",self),
		}
	}

}



impl fmt::Display for BackupStatistics {
	fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
		let output = format!(r#"
			read phase cost {}us
			split phase cost {}us
			hash phase cost {}us
			dedup phase cost {}us
			extract phase cost {}us
			matching phase cost {}us
			read base phase cost {}us
			delta phase cost {}us
			write phase cost {}us
			backup totally cost {}us
			data len in total:{}B
			after dedup in total:{}B({:.2}%)
			after delta in total:{}B({:.2}%)
			base chunk len:{}B,
			delta chunk origin len:{}B,
			total compress ratio:{:.2}%
			gear hash time:{}us
			pack feature time:{}us
			odess sample number:{}
			odess sample recoder:{}
			"#,
			self.read_phase_time,
			self.split_phase_time,
			self.hash_phase_time,
			self.dedup_phase_time,
			self.extract_phase_time,
			self.matching_phase_time,
			self.read_base_phase_time,
			self.delta_phase_time,
			self.write_phase_time,
			self.total_time,
			self.origin_len,
			self.after_dedup_len,
			self.dedup_ratio(),
			self.after_delta_len,
			self.delta_ratio(),
			self.base_chunk_len,
			self.delta_chunk_origin_len,
			self.total_ratio(),
			self.gear_hash_time,
			self.pack_feature_time,
			self.odess_sample_num,
			self.odess_sample_recorder
		);
		write!(f,"{}",output)
	}
}
